/**********************************************************************/
/*                                                                    */
/*           File bws1.c:  Multiprocessor Simulation Model 1          */
/*                                                                    */
/*  This is a synchronous model of a multiprocessor memory-bus sub-   */
/*  system with random request selection;  it appears in Figure 5.4.  */
/*                                                                    */
/**********************************************************************/
/*  KJC (10/10/95) - Changed <> to "" on include statement            */
/**********************************************************************/
#include "smpl.h"

#define busy 1

real
  p=0.250,         /* local memory miss rate            */
  treq[17],        /* next request time for processor   */
  tn=1.0E6;        /* earliest-occurring request time   */
int
  N=8,M=4,nB=2,    /* no. processors, memories, & buses */
  module[17],bus,  /* memory & bus facility descriptors */
  nbs=0,           /* no. busy buses in current cycle   */
  req[17],         /* currently-requested memory module */
  next=1;          /* arbitration scan starting point   */

/*-------------------  MEMORY-BUS BANDWIDTH MODEL  -------------------*/
main()
  {
    int event,i,n;
    smpl(0,"Bandwidth Model");
    bus=facility("bus",nB);
    for (i=1; i<=M; i++) module[i]=facility("module",1);
    for (n=1; n<=N; n++) {req[n]=0; next_access(n);}
    schedule(1,tn,0);
    while (time()<10000.0)
      {
        cause(&event,&n);
        switch(event)
          {
            case 1:  begin_cycle(); break;
            case 2:  req_module(n); break;
            case 3:  end_cycle(n);  break;
          }
      }
    printf("bw = %.3f\n",U(bus));
  }

/*--------------------  COMPUTE NEXT ACCESS TIME  -------------------*/
next_access(n)
  int n;
    {
      real t;
      t=floor(log(ranf())/log(1.0-p))+time();
      treq[n]=t; if (t<tn) then tn=t;
    }

/*----------------------  EVENT 1:  BEGIN CYCLE  ---------------------*/
begin_cycle()
  {
    int i,n=next; real t,tmin=1.0E6;
    for (i=0; i<N; i++)
      {
        if (!req[n]) then
          { /* in this version, req[n] always is 0 here */
            if ((t=treq[n])==tn)
              then
                {req[n]=random(1,M); schedule(2,0.0,n);}
              else if (t<tmin) then tmin=t;
          }
        n=(n%N)+1;
      }
    next=(next%N)+1; tn=tmin;
  }

/*----------------  EVENT 2:  REQUEST MEMORY AND BUS  ----------------*/
req_module(n)
  int n;
    {
      if (status(module[req[n]])!=busy&&status(bus)!=busy)
        then
          {
            request(module[req[n]],n,0); request(bus,n,0);
            nbs++; schedule(3,1.0,n);
          }
      else {req[n]=0; if (++treq[n]<tn) then tn=treq[n];}
    }

/*-----------------------  EVENT 3:  END CYCLE  ----------------------*/
end_cycle(n)
  int n;
    {
      release(bus,n); release(module[req[n]],n);
      req[n]=0; next_access(n);
      if (--nbs==0) then schedule(1,tn-time(),0);
    }
